use std::sync::{LazyLock, OnceLock};

use sqlx::{postgres::PgPoolOptions, PgPool,Executor};
use tools::global_defin::{config::global_config, tokio_runtime::get_rt};
use tracing::info;


pub static DB: LazyLock<Persistence> = LazyLock::new(|| {
	let pool = get_rt().block_on(r());
	Persistence { pool }
});

async fn r() -> PgPool {
	PgPoolOptions::new()
		.max_connections(global_config().db_max_conn_num.unwrap_or(10))
		.after_connect(|conn, _meta| {
			Box::pin(async move {
				info!("新增数据库连接:{conn:?}");
				conn
					.execute("SET application_name = 'sip_app'; set time zone 'Asia/Shanghai';")
					.await?;

				Ok(())
			})
		})
		.connect(global_config().db_url)
		.await
		.expect("连接数据库出现异常。。")
}
/**
 * 持久层的读取与写入组件。
 * 此组件在一个系统当中只有一个对象。
 * 多个对象的出现
 */
pub struct Persistence {
  pub pool: PgPool,
}

///初始化数据库连接池的操作 ,此操作由于需要阻塞，所以需要在启动时单独进行执行
pub fn sqlx_pool() -> &'static PgPool {
  static POOL: OnceLock<PgPool> = OnceLock::new();
  POOL.get_or_init(|| {
    get_rt().block_on(async move {
      PgPoolOptions::new()
        .max_connections(global_config().db_max_conn_num.unwrap_or(10))
				.after_connect(|conn, _meta| {
					Box::pin(async move {
						conn
							.execute("SET application_name = 'sip_esl'; set time zone 'Asia/Shanghai';")
							.await?;
		
						Ok(())
					})
				})
        .connect(global_config().db_url)
        .await
        .expect("连接数据库出现异常。。")
    })
  })
}

/// 查询并返回一个值..如果数据库未得到需要的数据.则使用给出的默认值
/// 默认值的类型必须与查询的返回值类型一致
/// 查询使用第一列的数据
/// 注意:当出现语法错误时,也会给出默认值
#[macro_export]
macro_rules! query_value (
	($pool:expr, $query:expr,$default:expr, $($args:expr),*) => ({
		use sqlx::Row;
		let value = sqlx::query($query)
			$(.bind($args))*
			.map(|r: sqlx::postgres::PgRow| r.try_get(0).unwrap_or($default))
			.fetch_one($pool)
			.await;

		match value {
			Ok(v) => v,
			Err(sqlx::error::Error::RowNotFound) => {
				tracing::debug!("没有数据,给默认值");
				$default
			}
			Err(e) => {
				tracing::error!("异常:{e:?}..,给出默认值");
				$default
			}
		}
	})
);

/// 查询并返回一个结构对象的值.
#[macro_export]
macro_rules! query_one (
	($out_struct:path,$pool:expr, $query:expr, $($args:tt),*$(,)?) => ( {
			sqlx::query_as::<sqlx::Postgres,$out_struct>($query)
			$(.bind($args))*
			.fetch_one($pool)
			.await
	})
);

/// 查询并返回一个结构对象的值.
/// 当不存在时返回Ok(None)
#[macro_export]
macro_rules! query_optional (
	($out_struct:path,$pool:expr, $query:expr, $($args:tt),*$(,)?) => ( {
			sqlx::query_as::<sqlx::Postgres,$out_struct>($query)
			$(.bind($args))*
			.fetch_optional($pool)
			.await
	})
);

/// 查询并返回一个结构对象的值.
/// 当不存在时返回Ok(None)
#[macro_export]
macro_rules! query_all (
	($out_struct:path,$pool:expr, $query:expr, $($args:tt),*$(,)?) => ( {
			sqlx::query_as::<sqlx::Postgres,$out_struct>($query)
			$(.bind($args))*
			.fetch_all($pool)
			.await
	})
);